
#include "paramconfig.h"
#include "common.h"
using namespace common;
#include "inifile.h"
using namespace inifile;

#include "osipparser2/osip_port.h"

#include <cctype> // export function toupper
#include <algorithm> // export function transform
#include <iterator> // export function back_inserter
#include <stdexcept>
using namespace std;



ConfigParam::ConfigParam() : mFrom(0), mServerUri(0)
{
}

bool ConfigParam::load_config(const std::string& filepath/* = "./config.ini"*/)
{
    IniFile config;

    if (RET_OK != config.Load(filepath))
    {
        std::string err("Can not open config file:");
        err += filepath;
        err += "\n";
        gen_config(filepath);
        err += "Now. the config file generated, you should modify and restart\n";
        throw std::runtime_error(err);
        return false;
    }

    config.GetBoolValueOrDefault("Log", "SipLogEnable", &mEnableLog, false);
    config.GetIntValueOrDefault("Log", "LogLevel", &mLogLevel, 7);
    if (mLogLevel < 0 || mLogLevel > 8)
    {
        throw std::runtime_error("[Log][LogLevel] level beyond! select from 0-8");
        return false;
    }
    config.GetStringValueOrDefault("Log", "LogFileName", &mLogFileName, "log.log");

    config.GetStringValueOrDefault("Main", "Address", &mLocalAddress, "");
    config.GetIntValueOrDefault("Main", "Port", &mLocalPort, 0);

    int ret = config.GetStringValue("Main", "FromUri", &mFromString);
    if (ret != RET_OK)
    {
        throw std::runtime_error("[Main][FromUri] Can not be empty!");
        return false;
    }
    // parse from uri
    osip_from_init(&mFrom);
    if (OSIP_SUCCESS != osip_from_parse(mFrom, mFromString.c_str()))
    {
        throw std::runtime_error("[Main][FromUri] invalid!");
        return false;
    }
    // parse route uri
    std::string server;
    config.GetStringValueOrDefault("Main", "RouteUri", &mServerString, "");
    if (!server.empty())
    {// parse from uri
        osip_uri_init(&mServerUri);
        if (OSIP_SUCCESS != osip_uri_parse(mServerUri, mServerString.c_str()))
        {
            throw std::runtime_error("[Main][RouteUri] invalid!");
            return false;
        }
    }
    config.GetStringValueOrDefault("Main", "AgentText", &mUserAgentText, "");

    config.GetIntValueOrDefault("Reg", "RegExpires", &mRegExpires, 120);
    config.GetBoolValueOrDefault("Reg", "RegAfterLoad", &mRegAfterLoad, false);
    config.GetBoolValueOrDefault("Reg", "RegAutoMasquerade", &mRegContactAutoMasquerade, false);

    config.GetBoolValueOrDefault("Call", "AutoAnswer", &mAutoAnswerCall, true);

    return true;
}

bool ConfigParam::gen_config(const std::string& filepath /*= "./config.ini"*/)
{
    IniFile config;

    config.SetBoolValue("Log", "SipLogEnable", true);
    config.SetComment("Log", "SipLogEnable", "# enable or disable sip stack log, default is true");
    config.SetIntValue("Log", "LogLevel", 7);
    config.SetComment("Log", "LogLevel", "# log level 0 - 7(TRACE_LEVEL0 - TRACE_LEVEL7), default is 7");
    config.SetStringValue("Log", "LogFileName", "siplog.log");
    config.SetComment("Log", "LogFileName", "# log file path name for sip stack log, default is siplog.log");
    config.SetComment("Log", "", "\n## log settings\n");

    config.SetStringValue("Main", "Address", "");
    config.SetComment("Main", "Address", "# local address for sip, if left blank, sip will bind all interface, default is blank");
    config.SetIntValue("Main", "Port", 0);
    config.SetComment("Main", "Port", "# local port for sip register, default is 0 for random port");
    config.SetStringValue("Main", "FromUri", "");
    std::string FromUriComment(
        "# address of record which usually used as visible public, can not be blank!\n"
        "# likely as '\"display-name\" <sip:user-name[:password]@domain[:port][;parameters...]>[;parameters...]'\n"
        "# The optional 'display-name' is meant to be rendered by a human user interface.\n"
        "# The 'user-name' and 'password' is for authentication\n"
        "# The 'domain' and 'port' is the domian which 'user-name' belong\n"
        "# The optional 'transport' parameter used for sip protocol, UDP / TCP / TLS / DTLS, default is UDP\n"
        "# For example : \"wh-test\" <sip:198970:123456@10.18.0.200:55555;transport=udp>\n");
    config.SetComment("Main", "FromUri", FromUriComment);
    config.SetStringValue("Main", "RouteUri", "");
    std::string RouteUriComment(
        "# Proxy server address and port for registration, If left blank, server address would automatically derived from `FromUri`.\n"
        "# likely as '<sip:domain[:port];lr>'\n"
        "# The 'lr' parameter means loose routing, message is routed through this address but the Request Uri header is not modified.\n"
        "#   Without this parameter, the Request Uri header and route are both specified as this address.\n"
        "# For exapmle : <sip:cn-zz-bgp-1.natfrp.cloud:45003;lr>\n"
        "#               <sip:s0.s100.vip:8395;lr>\n"
        "#               <sip:10.18.0.200:55555>\n");
    config.SetComment("Main", "RouteUri", RouteUriComment);
    config.SetStringValue("Main", "AgentText", "ZKSipAgent/0.1");
    config.SetComment("Main", "AgentText", "# text in User-Agent header, default is blank and auto filled by eXosip.");
    config.SetComment("Main", "", "\n## Main settings\n");

    config.SetIntValue("Reg", "RegExpires", 120);
    config.SetComment("Reg", "RegExpires", "# register expires time for seconds in Expires header, default is 120");
    config.SetBoolValue("Reg", "RegAfterLoad", false);
    config.SetComment("Reg", "RegAfterLoad", "# auto send register after load configuration file, default is false");
    config.SetBoolValue("Reg", "RegAutoMasquerade", false);
    config.SetComment("Reg", "RegAutoMasquerade", "# auto masquerade contact field with rport and received when register, default is false");
    config.SetComment("Reg", "", "\n## Register settings\n");

    config.SetBoolValue("Call", "AutoAnswer", true);
    config.SetComment("Call", "AutoAnswer", "# auto answer for call, default is true");
    config.SetComment("Reg", "", "\n## Call settings\n");

    config.SaveAs(filepath);

    return true;
}

std::string ConfigParam::get_from() const
{
    // hide password field and port field
    std::string from(mFromString);
    size_t pos = from.find(mFrom->url->password);
    if (mFrom->url->password && pos != std::string::npos)
    {
        from.replace(pos - 1, strlen(mFrom->url->password) + 1, "");
    }
    pos = from.find(mFrom->url->port);
    if (mFrom->url->port && pos != std::string::npos)
    {
        from.replace(pos - 1, strlen(mFrom->url->port) + 1, "");
    }
    return from;
}

std::string ConfigParam::get_protocol() const
{
    std::string transport = "UDP";
    osip_uri_param_t *param = 0;
    osip_uri_uparam_get_byname(mFrom->url, "transport", &param);
    if (param)
    {
        transport = param->gvalue;
    }
    return transport;
}

const char* ConfigParam::get_displayname_str() const
{
    return mFrom->displayname;
}

const char* ConfigParam::get_username_str() const
{
    return mFrom->url->username;
}

const char* ConfigParam::get_password_str() const
{
    return mFrom->url->password;
}

std::string ConfigParam::get_proxy() const
{
    // refer https://tools.ietf.org/html/rfc3261#page-57 The "userinfo" and "@" components of the SIP URI MUST NOT be present.
    std::string proxy;
    proxy += mFrom->url->scheme;
    proxy += ":";
    proxy += mFrom->url->host;
    if (strcmp(mFrom->url->port, "5060"))
    {
        proxy += ":";
        proxy += mFrom->url->port;
    }

    return proxy;
}

bool ConfigParam::exist_route() const
{
    return !mServerString.empty();
}

std::string ConfigParam::get_route() const
{
    std::string route;
    route += mServerString;
    return mServerString.c_str();
}

std::string ConfigParam::get_to(const std::string& target) const
{
    std::string to;
    to += mFrom->url->scheme;
    to += ":";
    to += target;
    to += "@";
    to += mFrom->url->host;
    if (strcmp(mFrom->url->port, "5060"))
    {
        to += ":";
        to += mFrom->url->port;
    }
    return to;
}


